#include "encode_url.hpp"

#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cassert>

int UrlParser::hex_rmap[] = 
		{
			-1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1, // 4 x 8
			-1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1,
			0,  1,  2,  3,  4,  5,  6,  7, // '0'-'9'
			8,  9, -1, -1, -1, -1, -1, -1, // 8 x 8
			-1, 10, 11, 12, 13, 14, 15, -1, // 'A'-'F'
			-1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1, // 12 x 8
			-1, 10, 11, 12, 13, 14, 15, -1, // 'a'-'f'
			-1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1 // 16 x 8
		};

std::string UrlParser::encode_uri(const std::string &sIn, 
		const std::string &unescaped_set)
{
	static const char XDIGIT[] = "0123456789ABCDEF";

	assert(unescaped_set.find('%') == std::string::npos);

	std::string sOut;
	for( std::size_t ix = 0; ix < sIn.size(); ix++ )
	{
		if((std::isalnum(sIn[ix])) ||
				(unescaped_set.find(sIn[ix]) != std::string::npos))
		{
			sOut += sIn[ix];
		}
		/* This is URI encoding, not HTTP forms:
		 * Space is encoded as '%20', not '+'. */
		else
		{
			sOut += '%';
			sOut += XDIGIT[ (sIn[ix] >> 4) & 0x0F ];
			sOut += XDIGIT[ sIn[ix] & 0x0F ];
		}
	}
	return sOut;
}


std::string UrlParser::decode_uri(const std::string &sIn)
{
	std::string sOut;
	for( std::size_t i = 0; i < sIn.size(); i++ )
	{
		const char& c = sIn[i];
		if (c != '%')
		{
			sOut += c;
		}
		else
		{
			if (i > sIn.size() - 2)
			{
				sOut += c;
			}
			else
			{
				const char& m = sIn[i+1];
				const char& n = sIn[i+2];
				if (std::isxdigit(m) && std::isxdigit(n))
				{
					unsigned char t = unhex_char(m, n) & 0xFF;
					sOut += t;
					i += 2;
				}
				else
				{
					sOut += c;
				}
			}
		}
	}
	return sOut;
}

